/*

Copyright (C) 2010  Christoph Schnack 

    This file is part of Tribuit.

    Tribuit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tribuit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Tribuit.  If not, see <http://www.gnu.org/licenses/>.
*/

package Wordcheck;

import java.awt.*;
import java.awt.event.*;
import java.math.BigDecimal;
import java.util.*;

import javax.swing.*;

import GuiTools.*;
import Settings.*;
import Statistics.Statistics;
import Storage.*;
import JukeBox.*;
import Mainframe.*;
import Settings.*;

import Wordcheck.WordcheckPreSelection.PreOptionPanel;


/**
 * 
 * Wordcheck provides the GUI and logic for word check. It is invoked by WordcheckPreSelection.
 * 
 * @author Christoph Schnack
 * @see WordcheckPreSelection
 */

    
public class Wordcheck{
	TribuitFrame testFrame,corrFrame;
	JPanel testCenterPanel,correctPanel;
	BottomPanel bottomPanel;
	String vocNameA,vocNameB,vocName;
	HashMap<String,TermClass> termClassesA,termClassesB;
	Vector<String> categoriesA,categoriesB;
	boolean VERBOSE,TESTLANG2,TESTMETAS,TESTMODUS, TESTALLMEANINGS,WRITESTATISTIC,TESTSYNONYMS;
	int range,correct_points;
    String[] opts = {"ok"};
	Word[] wordsToTest;
	Word wordToTest;
    Vector<Word> WRONGWORDS = new Vector<Word>(),testvocabulary;
    Vector<String> WRONGANSWERS = new Vector<String>();
    int wttLength,rightCounter=0;
    InterrogationPanel iPanel;
    SolutionPanel solutionPanel;
    Storage MAINVOC;
	TribuitFrame MAINFRAME;
    TribuitMenu MENU;
    Statistics STATISTICS;
    Settings SET;
    Language LANG;
    GridBagConstraints centerGbc = new GridBagConstraints();
	
/**
 * Initializes the Wordcheck
 * 
 * @param stor MAINVOC of Tribuit
 * @param frame MAINFRAME of Tribuit
 * @param set SET setting object
 */
	public Wordcheck(boolean testlang2, PreOptionPanel op, Storage mainvoc,Settings set,Mainframe mf,TribuitMenu menu,Vector<Word> testvoc,String nA,String nB, HashMap<String,TermClass> tA, Vector<String> catsA, HashMap<String,TermClass> tB,Vector<String> catsB){
		MAINVOC = mainvoc;
		MAINFRAME =mf;
		SET = set;
		LANG = set.getLanguage();
		STATISTICS = MAINVOC.getStatistics();
		TESTLANG2=testlang2;
		TESTMETAS=op.isTestmetas();
		TESTMODUS=op.isTestmodus();
		TESTALLMEANINGS=op.isTestallmeanings();
		WRITESTATISTIC=op.isWriteStats();
		TESTSYNONYMS = op.isTestSynonyms();
		testvocabulary=testvoc;
		testvocabulary.trimToSize();
		vocNameA = nA;
		vocNameB = nB;
		vocName = vocNameA + " - " + vocNameB;
		termClassesA = tA;
		categoriesA = catsA;
		termClassesB = tB;
		categoriesB = catsB;
		MENU=menu;
		
		centerGbc.insets = new Insets(30,30,30,30);
		
		buildTestGUI();
	}
	
	/**
	 * Initializes the GUI
	 */
	
	private void buildTestGUI(){
		testFrame = new TribuitFrame(LANG.getWckWordcheck());
		solutionPanel = new SolutionPanel();
		correctPanel = new CorrectPanel();
		StartPanel startPanel = new StartPanel(LANG,new StartListener());
	//center panel
		testCenterPanel = new JPanel();
		testCenterPanel.setLayout(new GridBagLayout());
		testCenterPanel.setBorder(BorderFactory.createLineBorder(Color.black,2));
		testCenterPanel.add(startPanel);
		
	//bottom panel
		Vector<String> sections = new Vector<String>(), tcs = new Vector<String>();
		String s;
		for(Word w : testvocabulary){
			s = w.getTermclassA()+"/"+w.getTermclassB();
			if(!sections.contains(w.getLection())) sections.add(w.getLection());
			if(!tcs.contains(s)) tcs.add(s);
			
		}
		Collections.sort(sections,String.CASE_INSENSITIVE_ORDER);
		bottomPanel = new BottomPanel(SET,vocName,tcs,sections);
		
	//frame configuration
		testFrame.getContentPane().add(BorderLayout.NORTH,new Header(LANG.getWckWordcheck()));
		testFrame.getContentPane().add(BorderLayout.CENTER,new CustomScrollPane(testCenterPanel));
		testFrame.getContentPane().add(BorderLayout.SOUTH,bottomPanel);
		testFrame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e){
				testFrame.dispose();
				MENU.setWordcheckRunning(false);
				if(MAINFRAME.getState()==JFrame.ICONIFIED) MAINFRAME.setState(JFrame.NORMAL);
				MAINFRAME.requestFocus();
			}
		});
		testFrame.showUp(700,500,200,200);
		testFrame.setResizable(true);
		startPanel.grabFocusStartBtn();
	}
	
	
	/**
	 * If the test run is not finished it displays the next Word from 'wordsToTest'. Otherwise when the end is reached the result (in TESTMODE) or the term "finished" and the restart-button is shown.
	 */
				
	public void testNext(){
		if(range<wordsToTest.length-1){
			range++;
			bottomPanel.setWordRangeCounterLabel((range+1)+"/"+wordsToTest.length);
			bottomPanel.setCorrectAnswersCounterLabel(""+correct_points);
			wordToTest = wordsToTest[range];
			if(iPanel==null) iPanel = new InterrogationPanel(SET,this,wordToTest,termClassesA.get(wordToTest.getTermclassA()),categoriesA, termClassesB.get(wordToTest.getTermclassB()), categoriesB, new TestListener(this,SET),(TESTMODUS?new SkipListener():new SolveListener()));
			else iPanel.setWord(wordToTest,termClassesA.get(wordToTest.getTermclassA()),categoriesA,termClassesB.get(wordToTest.getTermclassB()),categoriesB);
			addToCenterPanel(iPanel);
			testFrame.packAndKeepBounds();
			testFrame.repaint();
			iPanel.focusFirstComponent();
			
		}
		else{
			if(!TESTMODUS && WRONGWORDS.size()>0){
				wordsToTest=WRONGWORDS.toArray(new Word[WRONGWORDS.size()]);
				WRONGWORDS.clear();
				range=-1;
				testNext();
				return;
			}
			else{
				FinishedPanel finishedPanel = new FinishedPanel();
				addToCenterPanel(finishedPanel);
				if(WRITESTATISTIC)STATISTICS.saveStatistics(false);
				finishedPanel.playSound();
				finishedPanel.focusButton();
			}
		}
	}
	
	public void addWrongAnswer(String s){
		WRONGANSWERS.add(s);
	}
	
	public void increaseWrongStatistic(){
		if(WRITESTATISTIC)STATISTICS.increaseWrongs(vocName,wordToTest.getName());
	}
	
	public void addWrongWord(){
		if(!WRONGWORDS.contains(wordToTest))WRONGWORDS.add(wordToTest);
	}
	
	/**
	 * Displays the correct Icon and waits for a few secounds
	 * Is invoked when the answer is correct.
	 * 
	 */
	public void testCorrect(){
		rightCounter++;
		if(WRITESTATISTIC)STATISTICS.increaseCorrects(vocName, wordToTest.getName());
		correct_points++;
		new Thread(new Runnable(){
			public void run(){
				SET.getJukeBox().playCorrect();
			}
		}).start();
		addToCenterPanel(correctPanel);
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				try{Thread.sleep(1500);}
				catch(Exception e){e.getMessage();}
				testNext();
			}
		});
	}
	
	public void jukeBoxPlayWrong(){
		SET.getJukeBox().playWrong();
	}
	
	public TribuitFrame getFrame(){ return testFrame;}
	public boolean getWriteStatistics(){ return WRITESTATISTIC;}
	public boolean getTestmodus(){ return TESTMODUS;}
	public boolean getTestLang2(){ return TESTLANG2;}
	public String getTestLang2Name(){ return !TESTLANG2?vocNameB:vocNameA;}
	public boolean getTestSynonyms(){ return TESTSYNONYMS;}
	public boolean getTestMetas(){ return TESTMETAS;}
	public InterrogationPanel getInputPanel(){ return iPanel;}
	
	public boolean isDisplayable(){return testFrame.isDisplayable();}
	
	/**
	 * Removes all components
	 * @param comp
	 */
	public void addToCenterPanel(JComponent comp){
		testCenterPanel.removeAll();
		testCenterPanel.add(comp,centerGbc);
		testFrame.packAndKeepBounds();
		testFrame.repaint();
	}
	
	
	class MetaElementHM extends HashMap<String,MetaElement>{
		Vector<String> keys = new Vector<String>();
		public MetaElementHM(){
			super();
		}
		
		public void putSorted(String s, MetaElement m){
			this.put(s, m);
			if(!keys.contains(s))keys.add(s);
		}
		
		public String[] getSortedKeys(){
			return keys.toArray(new String[keys.size()]);
		}
		
		public void clearAll(){
			keys.clear();
			this.clear();
		}
	}
	
	class FinishedPanel extends JPanel{
		JButton restartBtn;
		String rate;
		public FinishedPanel(){
			super();
			this.setLayout(new GridBagLayout());
			
			restartBtn = new JButton(LANG.getRestart());
			restartBtn.addActionListener(new StartListener());
			
			JCheckBox switchLanguageCB = new JCheckBox(LANG.getSwitchTestlanguage(),false);
			switchLanguageCB.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					TESTLANG2 = !TESTLANG2;
					//TODO set label of input textfield to new language name
				}
			});
			JLabel testFinishedLabel = new JLabel(LANG.getWckFinished());
			testFinishedLabel.setFont(new Font(Font.SERIF,Font.ITALIC,35));
			JPanel btnPanel = new JPanel();
			btnPanel.add(restartBtn);
			
			GridBagConstraints gbc = new GridBagConstraints();
			gbc.insets = new Insets(0,10,10,10);
			gbc.fill = GridBagConstraints.NONE;
			gbc.anchor = GridBagConstraints.CENTER;
			gbc.gridy=0;
			this.add(testFinishedLabel,gbc);
			if(TESTMODUS){
				//lyrical evaluation label
				JLabel resultEvaluationLabel = new JLabel();
				resultEvaluationLabel.setFont(new Font(Font.SERIF,Font.PLAIN,20));
				JLabel telLabel = new JLabel(LANG.getRating()+": ");
				telLabel.setFont(new Font(Font.SERIF,Font.BOLD,20));
				JPanel resultEvaluationPanel = new JPanel();
				resultEvaluationPanel.add(telLabel);
				resultEvaluationPanel.add(resultEvaluationLabel);
				
				//result values label
				JLabel resultLabel = new JLabel("");
				resultLabel.setFont(new Font(Font.SERIF,Font.PLAIN,20));
				JLabel rlLabel = new JLabel(LANG.getCorrect()+": ");
				rlLabel.setFont(new Font(Font.SERIF,Font.BOLD,20));
				JPanel resultPanel = new JPanel();
				resultPanel.add(rlLabel);
				resultPanel.add(resultLabel);
				
				if(WRONGANSWERS.size()>0){
					JButton testCorrectionsButton = new JButton(LANG.getCorrections());
					testCorrectionsButton.addActionListener(new CorrectionsListener());
					btnPanel.add(testCorrectionsButton);
				}
				
				rate = LANG.getWckFailed();
				int result = 0;
				if(correct_points>0){
					double quote = correct_points/((double) wttLength);
					result = (int) Math.round(quote*100);
					if(quote== 1) rate = LANG.getWckVeryWell();
					else{	if(quote>0.90 && quote<1) rate=LANG.getWckGood();
							else{	if(quote>0.80 && quote<=0.90) rate = LANG.getWckPleasable();
									else{	if(quote>0.70 && quote<=0.80) rate = LANG.getWckImprovable();
											else{	if(quote>0.50 && quote<=0.70) rate = LANG.getWckBad();
													else{ if(quote<=0.50) rate = LANG.getWckVeryBad();
					}		}		}		}		}
				} 
				resultEvaluationLabel.setText(rate);
				resultLabel.setText(correct_points+"/"+wttLength+" ("+result+"%)");
				
				gbc.anchor = GridBagConstraints.NORTHWEST;
				gbc.insets = new Insets(0,10,0,10);
				++gbc.gridy;
				this.add(resultPanel,gbc);
				++gbc.gridy;
				this.add(resultEvaluationPanel,gbc);
			}
			btnPanel.add(switchLanguageCB);
			gbc.insets = new Insets(10,10,10,0);
			++gbc.gridy;
			this.add(btnPanel,gbc);
		}
		
		public void focusButton(){
			restartBtn.grabFocus();
		}
		
		public void playSound(){
			if(TESTMODUS){
				SwingUtilities.invokeLater(new Runnable(){
					public void run(){
						if(rate.equals(LANG.getWckVeryWell()))SET.getJukeBox().playVeryWell();
						if(rate.equals(LANG.getWckGood())) SET.getJukeBox().playGood();
						if(rate.equals(LANG.getWckPleasable())) SET.getJukeBox().playPleasable();
						if(rate.equals(LANG.getWckImprovable())) SET.getJukeBox().playImprovable();
						if(rate.equals(LANG.getWckBad())) SET.getJukeBox().playBad();
						if(rate.equals(LANG.getWckVeryBad())) SET.getJukeBox().playVerybad();
						if(rate.equals(LANG.getWckFailed())) SET.getJukeBox().playTotallyFailed();
					}
				});
			}
		}
		
		class CorrectionsListener implements ActionListener{
			public void actionPerformed(ActionEvent e){
				if(corrFrame!=null && corrFrame.isDisplayable()){
					corrFrame.setState(JFrame.NORMAL);
					corrFrame.requestFocus();
					return;
				}
				corrFrame = new TribuitFrame(LANG.getCorrections());
				JPanel centerPanel = new JPanel(),answerPanel,noPanel,aPanel;
				centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
				SolutionPanel panel;
				JLabel answerLabel,noLabel;
				Font ansFont = new Font(Font.SERIF,Font.BOLD,14),numFont = new Font(Font.SERIF,Font.BOLD,20);
				GridBagConstraints agbc = new GridBagConstraints();
				agbc.anchor = GridBagConstraints.NORTHWEST;
				agbc.insets = new Insets(20,0,0,0);
				for(int i=0;i<WRONGWORDS.size();i++){
					noLabel = new JLabel((i+1)+".:");
					noLabel.setFont(numFont);
					noPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
					noPanel.add(noLabel);
					panel = new SolutionPanel(true);
					panel.setWord(WRONGWORDS.get(i));
					answerPanel = new JPanel(new GridBagLayout());
					answerLabel = new JLabel(LANG.getYouAnswered()+": ");;
					answerLabel.setFont(ansFont);
					agbc.fill = GridBagConstraints.NONE;
					answerPanel.add(answerLabel,agbc);
					agbc.gridx = 1;
					agbc.fill = GridBagConstraints.BOTH;
					answerPanel.add(new JLabel(WRONGANSWERS.get(i)),agbc);
					aPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
					aPanel.add(answerPanel);
					centerPanel.add(noPanel);
					centerPanel.add(panel);
					centerPanel.add(aPanel);
				}
				JButton corrCloseButton = new JButton(LANG.getClose());
				JPanel cobPanel = new JPanel();
				cobPanel.add(corrCloseButton);
				cobPanel.setBackground(GuiTools.BGCOLOR);
				corrCloseButton.addActionListener(new ActionListener(){
					public void actionPerformed(ActionEvent e){
						corrFrame.dispose();
					}
				});
				JPanel centerContainer = new JPanel(new GridBagLayout());
				agbc.fill = GridBagConstraints.BOTH;
				agbc.weighty = 0;
				agbc.weightx = 1;
				agbc.gridy =1;
				centerContainer.add(centerPanel,agbc);
				agbc.weighty = 1;
				agbc.gridy =2;
				centerContainer.add(new JPanel(),agbc);
				CustomScrollPane corrSP = new CustomScrollPane(centerContainer);
				corrSP.setPreferredSize(new Dimension(500,200));
				corrFrame.getContentPane().add(new Header(LANG.getCorrections()),BorderLayout.NORTH);
				corrFrame.getContentPane().add(corrSP,BorderLayout.CENTER);
				corrFrame.getContentPane().add(cobPanel,BorderLayout.SOUTH);
				corrFrame.setResizable(true);
				corrFrame.pack();
				corrFrame.setLocation(200,200);
				corrFrame.setVisible(true);
			}
		}
	}
	
	class StartListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			WRONGANSWERS=new Vector<String>();
			WRONGWORDS = new Vector<Word>();
			wordsToTest = testvocabulary.toArray(new Word[]{});
			wttLength = wordsToTest.length;
			range = -1;
			correct_points = 0;
			testNext();
		}
	}

	
	class SolveListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			if(WRITESTATISTIC)STATISTICS.increaseWrongs(vocName,wordToTest.getName());
			if(!WRONGWORDS.contains(wordsToTest[range]))WRONGWORDS.add(wordsToTest[range]);
			solutionPanel.setWord(wordToTest);
			addToCenterPanel(solutionPanel);
			solutionPanel.focusButton();
		}
	}
	
	class SkipListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			WRONGWORDS.add(wordsToTest[range]);
			WRONGANSWERS.add("-");
			if(WRITESTATISTIC)STATISTICS.increaseWrongs(vocName,wordToTest.getName());
			testNext();
		}
	}
	
	class SolutionPanel extends JPanel{
		JPanel termAPanel,termBPanel;
		JButton goOnBtn;
		GridBagConstraints mGbc;
		Font keyFont = new Font(Font.SERIF,Font.BOLD,13);
		Insets metaSpaceLeftInsets = new Insets(3,10,0,0), noSpaceInsets = new Insets(0,0,0,0);
		int fontSize = 25;
		
		public SolutionPanel(){
			this(false);
		}
		
		public SolutionPanel(boolean correctionVersion){
			super();
			if(correctionVersion) fontSize = 18;
			mGbc =  new GridBagConstraints();
			mGbc.anchor = GridBagConstraints.NORTHWEST;
			mGbc.fill = GridBagConstraints.BOTH;
			
			termAPanel = new JPanel();
			termAPanel.setLayout(new BoxLayout(termAPanel,BoxLayout.Y_AXIS));
			termBPanel = new JPanel();
			termBPanel.setLayout(new BoxLayout(termBPanel,BoxLayout.Y_AXIS));
			
			JLabel compliesLabel = new JLabel(LANG.getWckIsTranslated());
			compliesLabel.setFont(new Font(Font.SANS_SERIF,Font.ITALIC,fontSize));
			
			goOnBtn = new JButton(LANG.getGoOn());
			goOnBtn.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					testNext();
				}
			});
			this.setLayout(new GridBagLayout());
			GridBagConstraints sGBC = new GridBagConstraints();
			sGBC.anchor = GridBagConstraints.NORTHEAST;
			sGBC.fill = GridBagConstraints.NONE;
			sGBC.weightx=2;
			sGBC.gridx=0;
			this.add(termAPanel,sGBC);
			sGBC.gridx=1;
			sGBC.weightx=0;
			sGBC.insets = new Insets(0,15,0,15);
			this.add(compliesLabel,sGBC);
			sGBC.insets = new Insets(0,0,0,0);
			sGBC.anchor = GridBagConstraints.NORTHWEST;
			sGBC.gridx=2;
			sGBC.weightx=2;
			this.add(termBPanel,sGBC);
			if(!correctionVersion){
				sGBC.insets = new Insets(20,0,0,0);
				sGBC.anchor = GridBagConstraints.CENTER;
				sGBC.gridx=1;
				sGBC.gridy=2;
				this.add(goOnBtn,sGBC);
			}
		}
		
		public void setWord(Word w){
			termAPanel.removeAll();
			termBPanel.removeAll();
			if(!TESTLANG2){
				for(Meaning m : w.getMeaningVectorA()){
					termAPanel.add(new MeaningSolutionDisplay(m,termClassesA.get(w.getTermclassA())));
				}
				for(Meaning m : w.getMeaningVectorB()){
					termBPanel.add(new MeaningSolutionDisplay(m,termClassesB.get(w.getTermclassB())) );
				}
			}
			else{
				for(Meaning m : w.getMeaningVectorA()){
					termBPanel.add(new MeaningSolutionDisplay(m,termClassesA.get(w.getTermclassA())));
				}
				for(Meaning m : w.getMeaningVectorB()){
					termAPanel.add(new MeaningSolutionDisplay(m,termClassesB.get(w.getTermclassB())) );
				}
			}
		}
		
		private class MeaningSolutionDisplay extends JPanel{
			public MeaningSolutionDisplay(Meaning meaning,TermClass termClass){
				super();
				JLabel chiefMeaningLabel = new JLabel(meaning.getMeaningAsStringFull());
				chiefMeaningLabel.setAlignmentX(LEFT_ALIGNMENT);
				chiefMeaningLabel.setFont(new Font(Font.SANS_SERIF,Font.BOLD,fontSize));
				JLabel synonymsLabel = new JLabel(meaning.getSynonymsAsString());
				JPanel metaPanel = new JPanel();
				if(meaning.hasMeta()){
					metaPanel.setLayout(new GridBagLayout());
					mGbc.gridx = 0;
					mGbc.gridy = 0;
					mGbc.insets = metaSpaceLeftInsets;
					for(String key : termClass.getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							JLabel keyLabel = new JLabel(key+":");
							keyLabel.setFont(keyFont);
							keyLabel.setAlignmentX(LEFT_ALIGNMENT);
							JLabel valueLabel = new JLabel(meaning.getMetaElement(key));
							valueLabel.setAlignmentX(LEFT_ALIGNMENT);
							mGbc.gridx = 0;
							mGbc.weightx = 0;
							metaPanel.add(keyLabel,mGbc);
							mGbc.gridx = 1;
							metaPanel.add(valueLabel,mGbc);
							mGbc.gridx = 2;
							mGbc.weightx = 1;
							metaPanel.add(new JPanel(),mGbc);
							++mGbc.gridy;
						}
					}
				}
				this.setLayout(new GridBagLayout());
				mGbc.insets = noSpaceInsets;
				mGbc.gridy = 0;
				mGbc.gridx = 0;
				mGbc.weightx = 1;
				this.add(chiefMeaningLabel,mGbc);
				mGbc.gridy = 1;
				this.add(synonymsLabel,mGbc);
				mGbc.gridy = 2;
				this.add(metaPanel,mGbc);
				
			}
		}
		
		public void focusButton(){
			goOnBtn.grabFocus();
		}
	}
	
	private class CorrectPanel extends JPanel{
		public CorrectPanel(){
			super();
			this.setLayout(new BorderLayout());
			this.add(new JLabel(GuiTools.CORRECT_IMAGE), BorderLayout.CENTER);
		}
	}
}//test-class
